home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
dskut
/
p22v12.zip
/
PATCH22.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-08
|
24KB
|
570 lines
#include <conio.h>
#include <dos.h>
#include <ctype.h>
#undef tolower /* use function version instead of macro version */
#undef toupper
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*------------------------- PATCH22 ---------------------------------------
* just compile as: cl patch22.c
*
* exit value (byte):
* -5: error in patch command string
* -4: file with patch commands not found
* -3: file to be patched not found
* -2: error in patch commandline (if not silent help is displayed)
* -1: not used (reserved for calling through spawn functions)
* >= 0: total no of patches made
*-------------------------------------------------------------------------*/
/*----------------------------- Revision history ---------------------------
* 8-08-91: Released version 1.2
* 22-07-91: - The date/time stamp of a file is reset if any patches are made.
* - Added (simple) password protection option.
* 7-07-91: - If user chooces Quit, now breaks out of while loop, instead
* of spooling to end of file.
* - Corrected bug pointed out by Ernst Raedecker of Amsterdam:
* find function did not allow for search string matching within
* itself. (See patch22.doc)
* - Now the next search continues one byte after the start of the
* previous match.
* 12-05-91: cctos() converts character following \ to lowercase, changed
* ffindi() slightly.
* 11-05-91: Now checks for progress in conditions field (+A000 led to
* infinite loop). Added case insensitive option.
* 11-04-91: Added <Q>uit option to verbose patching.
* 5-04-91: Replaced function Abort by message (using stdarg).
* Now continues with next patch if taking patches from file and
* file to be patched not found.
* 28-02-91: Fixed bug in ffindf function (the first non-matching char after
* a match was not used as the starting char in the next search).
* 22-02-91: Added error message if 0 patches requested.
* 18-02-91: Command line patch didn't work, bug fixed.
* 03-02-91: Added \w char escape codes, replaced mallocs by static arrays,
* using scanf to read \x##, \w####, \### (see NB.2 in cctos).
* 02-02-91: Less silent; removed error in scanning upto ?; added missing
* breaks in switching for \ char escape codes.
*--------------------------------------------------------------------------*/
/*=========================== global help ==================================*/
#define ERR_EXIT { fprintf(stderr, sUsage, sProgram, sVersion, sAuthor, \
sProgram, sProgram, sProgram, sProgram); exit(0); }
char *sProgram = "PATCH22";
char *sVersion = "version 1.2";
char *sAuthor = "(C) J.A. Doornik, 8 August 1991.";
char sP22[] = { '«','p','2','2','_','»' }; /* signature */
char sPassword[] = "\0 gf ggv aewf bvsbago"; /* password: 21 chars+\0 */
/* leading \0 indicates no password; avoid .exe compression */
char *sUsage =
"\n%s %s: patches any file %s\n"
"\nUsage:\t%s fname +##*##si\?search_text\?new_text\?"
"\n or:\t%s @fname\n"
"\nfname\tfile to be patched"
"\n+##\t+ve or -ve offset from the start of the search text"
"\n*##\tmaximum number of patches"
"\ns\tsilent patch, default is confirm each patch"
"\ni\tcase insensitive patch, default is case sensitive"
"\n@fname\tfile with (multiple) %s commands, with format:"
"\n\tfname +##*##s\?search_text\?new_text\?"
"\ntext\tC-type character constant, possibly including:"
"\n\t\\a (07h), \\b (08h), \\f (0Ch), \\n (0Ah), \\r (0Dh), \\t (09h), \\v (0Bh);"
"\n\t\\### (octal byte, not more than 3 digits);"
"\n\t\\w#### (hexadecimal word, not more than 4 digits);"
"\n\t\\x## (hexadecimal byte, not more than 2 digits);"
"\n\t\\h (the rest of the text contains two-digit hexadecimal bytes)."
"\n\tThe characters \\ \? \' \" must be written as: \\\" \\\\ \\\? \\\' \\\"."
"\n\nEg.\t%s test *1\?\h0d0a00\?\\r\\n\\0\?"
"\nwhich makes one change, where the replace text equals the search text.\n";
/*=========================== global types =================================*/
typedef unsigned char byte; /* b */
typedef unsigned short bool; /* f */
typedef unsigned short word; /* w */
#define FALSE 0
#define TRUE !FALSE
struct Patch22 /* structure to store all patch info */
{
byte *sSearch, *sNew; /* search text and new text */
int cNew, cSearch; /* # of bytes in search text and new text */
int iMaxpatch, cPatch; /* maximum and actual number of patches */
int iMaxfind; /* maximum number of finds */
long lOffset; /* offset from start of search string */
};
/*=========================== global data ==================================*/
#define MAXPATLEN 1024 /* maximum length of a patch text */
static bool fVerbose_ = TRUE;
static int iColor_hi = 0x001f, iColor_lo = 0x0017;
static char *s16dots = "∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙";
static char *s16dots3 = "∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ∙∙ ";
int ffindfn(FILE *f, byte *s, int slen); /* prototypes */
int ffindfi(FILE *f, byte *s, int slen);
int (* ffindf)(FILE *, byte *, int) = ffindfn; /* case sensitive find */
/* --------------- files and internal buffer for in/output --------------- */
#define BUFLEN 20480 /* 20K buffer */
static byte inbuf_[BUFLEN];
static FILE *infile_, *comfile_; /* files are global variables */
unsigned uFdate, uFtime; /* date and time of file to be patched */
/*--------------------------- procedure message ----------------------------*/
void message(int exitcode, char *msg, ...)
{
va_list args;
fprintf(stderr, "%s error: ", sProgram);
va_start(args, msg); vfprintf(stderr, msg, args); va_end(args);
fprintf(stderr, ".\n");
if (exitcode != 0) exit(exitcode);
}
/*--------------------------- end procedure message ------------------------*/
/*------------------ open_infile/close_infile/open_comfile -----------------*/
int open_infile(char *infname) /* get file to be patched */
{
if ( (infile_ = fopen(infname, "r+b")) == NULL) /* read & write, binary */
{ message(0, "cannot open file %s", infname);
return(FALSE);
}
_dos_getftime(fileno(infile_), &uFdate, &uFtime); /* get file date/time */
setvbuf(infile_, inbuf_, _IOFBF, BUFLEN);
return(TRUE);
}
void close_infile(int npatches) /* close patched file */
{
if (npatches > 0)
_dos_setftime(fileno(infile_), uFdate, uFtime); /* reset file date */
fclose(infile_);
}
int open_comfile(char *comfname) /* get file with patch commands */
{
if ( (comfile_ = fopen(comfname, "r")) == NULL) /* read */
{ message(0, "cannot open file %s", comfname);
return(FALSE);
}
return(TRUE);
}
/*------------------ END open_infile/close_infile/open_comfile -------------*/
/*------------------------------- getpatch ---------------------------------*/
int getpatch(FILE *f, char *infname, byte *s)
{ /* gets fname +##*##s?search_text?new_text? from a file */
int ch, len;
do
{ fscanf(f, " "); /* skip white space */
ch = 0; fscanf(f, ";%n", &ch); /* check if there is a ; */
if (ch > 0) fscanf(f, "%*[^\n]"); /* skip comment lines upto \n */
} while (!feof(f) && ch > 0);
if (fscanf(f, " %s ", infname) != 1) return(EOF);
len = MAXPATLEN - 1; /* read upto first question mark */
while (--len > 0 && (ch = fgetc(f)) != EOF && ch != '\?')
if (ch != '\n') *s++ = ch;
*s++ = '\?';